﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Xml.Linq;
using Excel=Microsoft.Office.Interop.Excel;

namespace Oryon.Extensions.Data
{
    /// <summary>
    /// Extension methods for Data operations
    /// </summary>
    public static class Functions
    {
        /// <summary>
        /// Convert any DataTable content to XElement
        /// </summary>
        /// <param name="table">Source</param>
        /// <returns>XML Content in XElement form</returns>
        public static XElement ConvertToXElement(this DataTable table)
        {
            using (StringWriter sWriter = new StringWriter())
            {
                table.WriteXml(sWriter);
                return XElement.Parse(sWriter.ToString());
            }
        }

        /// <summary>
        /// Serialize any DataSet to a binary file
        /// </summary>
        /// <param name="dataSet">source dataSet object instance</param>
        /// <param name="output">Output file's full path</param>
        /// <returns>if process accomplished it's true</returns>
        public static bool BinarySerialize(this DataSet dataSet, out string output)
        {
            bool result = false;
            string fileName = Path.Combine(Environment.CurrentDirectory, string.Format("{0}.bin", Guid.NewGuid()));
            BinaryFormatter formatter = new BinaryFormatter();
            using (FileStream fStream = new FileStream(fileName, FileMode.Create))
            {
                formatter.Serialize(fStream, dataSet);
                result=true;
                output = fileName;
            }
            return result;
        }

        /// <summary>
        /// Serialize any object to JSON that's from T type  
        /// </summary>
        /// <typeparam name="T">source object's type</typeparam>
        /// <param name="source">source object's instance</param>
        /// <returns>if convertion is successed it returns JSON content otherwise it returns String.Empty</returns>
        public static string SerializeToJSON<T>(this T source)
        {
            string result = String.Empty;
            try
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
                using (MemoryStream mStream = new MemoryStream())
                {
                    serializer.WriteObject(mStream, source);
                    result = Encoding.Default.GetString(mStream.ToArray());
                }
            }
            catch
            {

            }

            return result;
        }

        /// <summary>
        /// Write any Entity Framework Collection's content into Excel
        /// </summary>
        /// <typeparam name="T">Entity Type</typeparam>
        /// <param name="source">Collection</param>
        /// <param name="filePath">Excel file path</param>
        /// <returns>true if succedded</returns>
        public static bool WriteToExcel<T>(this IEnumerable<T> source, string filePath)
        {
            bool result = false;
            if (!String.IsNullOrEmpty(filePath))
            {
                var excelApp = new Excel.Application { Visible = false };
                Excel.Workbook book = excelApp.Workbooks.Add();
                Excel.Worksheet sheet = excelApp.ActiveSheet;
                int currentRow = 1;
                int currentColumn = 1;
                var properties = typeof(T).GetProperties();

                foreach (var item in source)
                {
                    foreach (var property in properties)
                    {
                        if (property.PropertyType.Name != "EntityKey"
                            || property.PropertyType.Name != "EntityState")
                        {
                            sheet.Cells[currentRow, currentColumn].Value = property.GetValue(item, null);
                            currentColumn++;
                        }
                    }
                    currentRow++;
                }

                book.SaveAs(filePath);
                excelApp.Application.Quit();
                result = true;
            }
            return result;
        }

        /// <summary>
        /// Get any Datatable' s column names
        /// </summary>
        /// <param name="table">Source datatable object instance</param>
        /// <returns>if DataTable instance has columns it returns column names in a List</returns>
        public static List<string> GetColumnNames(this DataTable table)
        {
            List<string> columnNames = null;

            if (table.Columns.Count > 0)
            {
                columnNames = new List<string>();
                foreach (DataColumn column in table.Columns)
                    columnNames.Add(column.ColumnName);
            }

            return columnNames;
        }

        /// <summary>
        /// Return true if source DataTable object' s instance has rows
        /// </summary>
        /// <param name="table">Source datatable object instance</param>
        /// <returns>are there any row it returns true</returns>
        public static bool HasRows(this DataTable table)
        {
            return table.Rows.Count > 0;
        }

        /// <summary>
        /// Convert a data table content to HTML
        /// </summary>
        /// <param name="table">Source datatable object</param>
        /// <returns>it return HTML Content</returns>
        public static string WriteToHTML(this DataTable table)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(string.Format("<h2>{0}</h2><br/>", table.TableName));
            builder.Append("<table>");
            var columnNames=table.GetColumnNames();
            foreach (var columnName in columnNames)
                builder.Append(string.Format("<th>{0}</th>", columnName));
            builder.Append("</tr>");

            foreach (DataRow row in table.Rows)
            {
                builder.Append("<tr>");
                foreach (var columnName in columnNames)
                {
                    builder.Append(string.Format("<td>{0}</td>", row[columnName].ToString()));
                }
                builder.Append("</tr>");
            }

            builder.Append("</table>");
            return builder.ToString();
        }

        /// <summary>
        /// Convert a DataSet content to HTML
        /// </summary>
        /// <param name="dataSet">Source DataSet object instance</param>
        /// <returns>it returns HTML content of given DataSet</returns>
        public static string WriteToHTML(this DataSet dataSet)
        {
            StringBuilder builder = new StringBuilder();

            builder.Append(string.Format("<h1>{0}</h1><br/>",dataSet.DataSetName));

            foreach (DataTable table in dataSet.Tables)
                builder.Append(string.Format("<div>{0}</div>", table.WriteToHTML()));

            builder.Append("<br/>");
            return builder.ToString();
        }
    }
}
